#coding:utf-8
'''
create on 2017-07-19
@author:sandy
'''

import logging
import time
import random
import TableBase
import mjConst
import mjBuild
import mjCheck


class BaseCmd(object):
    def __init__(self):
        self.seatNum = 0
        self.cardId = 0
        self.chi = 0
        self.peng = 0
        self.mgang = 0
        self.agang = 0
        self.hu = 0
        self.priority = 10 

    def init(self,seatNum,cardId,chi,peng,mgang,agang,hu):
        self.seatNum = seatNum
        self.cardId = cardId
        self.chi = int(chi)
        self.peng = int(peng)
        self.mgang = int(mgang)
        self.agang = int(agang)
        self.hu = int(hu)
        if chi:
            self.priority = 3
        if peng:
            self.priority = 2
        if mgang:
            self.priority = 2
        if agang:
            self.priority = 2
        if hu:
            self.priority = 1


class RoundCmd(object):
    def __init__(self):
        self.cmds = []

    def newCmd(self,seatNum,cardId,chi,peng,mgang,agang,hu):
        cmd = BaseCmd()
        cmd.init(seatNum,cardId,chi,peng,mgang,agang,hu)
        self.addCmd(cmd)
        
    def addCmd(self,cmd):
        self.cmds.append(cmd)

    def delCmd(self,cmd):
        self.cmds.remove(cmd)

    def reset(self):
        self.cmds = []

    def sortCmd(self):
        #priority数字越小 优先级越高 胡>碰(杠)>吃  priority相同座位号越小 优先级越高
        self.cmds = sorted(self.cmds,key=lambda x:(x.priority,x.seatNum))
        pass

    def getOneCmd(self):
        if len(self.cmds) > 0:
            return self.cmds[0]
        return None

    def popCmd(self):
        self.cmds.pop(0)


class Player(object):
    
    def __init__(self):
        self.init()

    def init(self):
        self.discard = 0 #万1条2饼3
        self.handleCards = []
        self.pengCards = []
        self.mgangCards = []
        self.agangCards = []

    def getHandleCards(self):
        return self.handleCards

    def getPengCards(self):
        return self.pengCards

    def getMGangCards(self):
        return self.mgangCards
    
    def getAGangCars(self):
        return self.agangCards
        
    def getDiscard(self):
        return self.discard
    
    def setDiscard(self,dis):
        self.discard = dis

    def setHandleCards(self,card):
        self.handleCards.append(card)

    def pengPai(self,cardId):
        t = cardId / 100
        v = cardId % 10
        tmp = []
        for id in self.handleCards:
            ht = id / 100
            hv = id % 10
            if t == ht and v == hv:
                tmp.append(id)
        if len(tmp) >= 2:
            for i in range(2):
                self.handleCards.remove(tmp[i])
                self.pengCards.append(tmp[i])
            self.pengCards.append(cardId)
            return tmp[:2]
        else:
            return []

    def mGangPai(self,cardId):
        t = cardId / 100
        v = cardId % 10
        tmp = []
        for id in self.pengCards:
            ht = id / 100
            hv = id % 10
            if t == ht and v == hv:
                tmp.append(id)
        if len(tmp) == 3:
            for i in range(3):
                self.pengCards.remove(tmp[i])
                self.mgangCards.append(tmp[i])
            self.mgangCards.append(cardId)
            return tmp
        else:
            return []

    def aGangPai(self,cardId):
        t = cardId / 100
        v = cardId % 10
        tmp = []
        for id in self.handleCards:
            ht = id / 100
            hv = id % 10
            if t == ht and v == hv:
                tmp.append(id)
        if len(tmp) == 3:
            for i in range(3):
                self.handleCards.remove(tmp[i])
                self.agangCards.append(tmp[i])
            self.agangCards.append(cardId)
            return tmp
        else:
            return []


class MjTable(TableBase.TableBase):
    def __init__(self, tid, hc):
        TableBase.TableBase.__init__(self, tid, hc)
        self.init()

    def init(self):
        self.seatCount = self.getSeatCount()
        self.ownerId = 0  #房主UserId
        self.hallId = 0   #
        self.playModel=0  #模式 几人场
        self.maxRound = 0 #场次
        self.tableIdStr = u""
        self.curRound = 0
        self.state = mjConst.STATE_TABLE_INIT
        self.tableCards = []

        self.playerMap = {}  #seat-->player

        # self.handleCards = []
        # self.pengCards = []
        # self.gangCards = []
        # self.anGangCards = []
        self.lastTime = 0
        self.readyTime = 0
        self.dealTime = 0
        self.startTime = 0
        self.randN1 = 0
        self.randN2 = 0
        self.bankerSeat = -1 #庄家的座位号
        self.eastSeat = 0
        self.roundCmd = RoundCmd()
        self.lastPlaySeat = -1

    def dismissTable(self):
        self.init()

    def resetRoundCmd(self):
        self.roundCmd.reset()

    def setTableInfo(self,uid,hallId,playModel,maxRound,tableIdStr):
        self.ownerId = uid
        if self.hallId != hallId:
            logging.warn("setTableInfo hallId error self.hallId=%d hallId=%d",self.hallId,hallId)
        self.playModel=playModel
        self.maxRound = maxRound
        self.tableIdStr = tableIdStr
        self.state = mjConst.STATE_TABLE_WAIT
        self.lastTime = time.time()
        self.magicCardId = 405
        pass

    

    def getTableInfo(self):
        d = {}
        d["model"] = self.playModel
        d['maxround'] = self.maxRound
        return d

    def onUserEnter(self,uid,seat):
        logging.debug("onUserEnter uid=%d endter table and tableId=%d seat=%d",uid,self.id,seat)
        

    def onUserLeave(self,uid,reason):
        logging.debug("onUserLeave uid=%d leaveTable tableId=%d reason=%d",uid,self.id,reason)
        if self.getUserCount() == 0:
            self.dismissTable()
        pass

    def checkTable(self):
        now = time.time()
        if self.state == mjConst.STATE_TABLE_WAIT and self.getUserCount() == 0 and self.ownerId > 0 and (now-self.lastTime) > 10:
            logging.warn(u"player request createTable more than 10s,player not enter table")
            pass
        
        if self.state == mjConst.STATE_TABLE_WAIT and self.getUserCount() == self.seatCount:
            logging.debug(u"1111111111 HallId=%d tableId=%d 客户端开始洗牌 垒牌动作",self.hallId,self.id)
            for i in range(self.seatCount):
                p = Player()
                self.playerMap[i] = p
            self.state = mjConst.STATE_TABLE_READY
            self.readyTime = now
            self.sendXiPai()

        if self.state == mjConst.STATE_TABLE_READY and (now - self.readyTime) >= 5:
            logging.debug(u"2222222222 HallId=%d tableId=%d 客户端开始掷骰子--->抓牌----->等待",self.hallId,self.id)
            self.state = mjConst.STATE_TABLE_DEAL
            self.dealTime = now
            self.sendFaPai()

        if self.state == mjConst.STATE_TABLE_DEAL and (now - self.dealTime) >= 15:
            logging.debug(u"3333333333 HallId=%d tableId=%d 客户端抓牌完毕 等待开始游戏",self.hallId,self.id)
            self.state = mjConst.STATE_TABLE_PLAY
            self.startTime = now

        if self.state == mjConst.STATE_TABLE_PLAY and (now - self.startTime) >= 1000:
            logging.debug(u"444444444 HallId=%d tableId=%d 客户端打牌超时",self.hallId,self.id)
        

    def sendXiPai(self):
        if self.bankerSeat == -1:
            self.bankerSeat = self.getSeatId(self.ownerId)
            self.eastSeat = random.randint(1,self.seatCount)
        else:
            self.bankerSeat = (self.bankerSeat + 1) % self.seatCount
        packet = mjBuild.xiPai(self.bankerSeat,self.eastSeat)
        self.broadcast(packet)
        self.tableCards = mjCheck.instance.randomMjs()


    def sendFaPai(self):
        self.randN1 = random.randint(1,6)
        self.randN2 = random.randint(1,6)
        logging.debug("randN1 = %d",self.randN1)
        logging.debug("rangN2 = %d",self.randN2)

        for key in self.playerMap:
            p = self.playerMap.get(key)
            p.init()
        
        for i in range(13):
            for j in range(self.seatCount):
                p = self.playerMap.get(j)
                p.setHandleCards(self.tableCards.pop(0))
        zhuangPlayer = self.playerMap.get(self.bankerSeat)
        zhuangPlayer.setHandleCards(self.tableCards.pop(0))

        for i in range(self.seatCount):
            p = self.playerMap.get(i)
            handlecards = p.getHandleCards()
            pkt = mjBuild.faPai(self.randN1,self.randN2,handlecards)
            user = self.getUser(i)
            logging.debug("uid=%d seat=%d cards=%s",user.uid,user.getSeatNum(),str(handlecards))
            user.sendPacket(pkt)


    def playCard(self,uid,card):
        user = self.getUserByUid(uid)
        seat = user.getSeatNum()
        if (self.lastPlaySeat + 1) % self.seatCount == seat:
            self.lastPlaySeat = seat
            logging.debug("uid=%d seat=%d playCard card=%d",uid,seat,card)
            curCards = self.playerMap.get(seat).getHandleCards()
            if card in curCards:
                self.broadcast(mjBuild.daPai(seat,card))
                others = self.getAllUsersExcept(uid)
                cpgh = False
                for other in others:
                    o_seat = other.getSeatNum()
                    p = self.playerMap.get(o_seat)
                    discard = p.getDiscard()
                    if(card / 100 == discard / 100):
                        continue
                    handlecards = p.getHandleCards()
                    chi = False
                    peng = mjCheck.instance.checkPeng(card,handlecards,self.magicCardId)
                    gang = mjCheck.instance.checkGang(card,handlecards,self.magicCardId)
                    agang = False
                    hu = mjCheck.instance.checkHu(card,handlecards,self.magicCardId)
                    if chi or peng or gang or hu:
                        if seat == 1 or seat == 2:
                            if o_seat < seat:
                                o_seat += self.seatCount
                        self.roundCmd.newCmd(o_seat,card,chi,peng,gang,agang,hu)
                        cpgh = True
                if cpgh == True:
                    #cmd排序-->发出第一个cmd 等待cmd回复
                    self.state = mjConst.STATE_TABLE_CPGH
                    self.roundCmd.sortCmd()
                    cmd = self.roundCmd.getOneCmd()
                    logging.debug("seat=%d打完牌card=%d其他玩家可以吃碰杠胡",seat,card)
                    self.executeNextCmd(cmd)
                    pass
                else:
                    self.state = mjConst.STATE_TABLE_BUPAI
                    logging.debug("seat=%d打完牌card=%d其他玩家不能吃碰杠胡",seat,card)
                    self.executeBuPai(seat)
            else:
                user.sendPacket(mjBuild.playCard(seat,card,mjConst.MJ_ERR_CARD_ERROR))
        else:
            logging.debug(u"打牌顺序有问题 last=%d now=%d",self.lastPlaySeat,seat)


    def chiPGH(self,uid,cpgh):
        user = self.getUserByUid(uid)
        seat = user.getSeatNum()
        cmd = self.roundCmd.getOneCmd()
        if cmd and cmd.seatNum % self.seatCount == seat:
            if cpgh == 0:
                #弃
                self.roundCmd.delCmd()
                nextcmd = self.roundCmd.getOneCmd()
                if nextcmd:
                    self.executeNextCmd(nextcmd)
                else:
                    logging.debug("cmdList中没有了,下一玩家正常补牌")
                    self.executeBuPai(seat)
                pass
            elif cpgh == 1:
                #吃
                if cmd.chi:
                    self.lastPlaySeat = seat
                    self.roundCmd.reset()
                else:
                    logging.warn(u'1吃牌失败')
                pass
            elif cpgh == 2:
                #碰
                if cmd.peng:
                    self.lastPlaySeat = seat
                    self.roundCmd.reset()
                    ret = self.playerMap.get(seat).pengPai(cmd.cardId)
                    if len(ret) == 2:
                        self.broadcast(mjBuild.cpgh(seat,2,tmp[:2]))
                    else:
                        logging.warn(u"碰出现异常")
                else:
                    logging.warn(u'2碰牌失败')
                pass
            elif cpgh == 3:
                #明杠
                if cmd.gang:
                    self.lastPlaySeat = seat
                    self.roundCmd.reset()
                    ret = self.playerMap.get(seat).mGangPai(cmd.cardId)
                    if len(ret) == 3:
                        self.broadcast(mjBuild.cpgh(seat,3,ret))
                        logging.debug("明杠牌后--->补牌")
                        self.executeBuPai(seat)
                    else:
                        logging.warn(u"明杠出现异常")
                else:
                    logging.warn(u"3明杠牌失败")
                pass
            elif cpgh == 4:
                #暗杠
                if cmd.agang:
                    self.lastPlaySeat = seat
                    self.roundCmd.reset()
                    cardId = cmd.cardId
                    ret = self.playerMap.get(seat).aGangPai(cmd.cardId)
                    if len(ret) == 3:
                        user.sendPacket(mjBuild.cpgh(seat,4,ret))
                        self.broadcastExcept(mjBuild.cpgh(seat,4,[]),uid)
                        logging.debug("明杠牌后--->补牌")
                        self.executeBuPai(seat)
                    else:
                        logging.warn(u"暗杠出现异常")
                else:
                    logging.warn(u"4暗杠牌失败")
                pass
            elif cpgh == 5:
                #胡
                if cmd.hu:
                    self.lastPlaySeat = seat
                    self.roundCmd.reset()
                    cardId = cmd.cardId
                    self.broadcast(mjBuild.cpgh(seat,5,[]))
                    logging.debug(u"胡牌")
                else:
                    logging.warn(u"5胡牌失败")
                pass
        else:
            logging.warn(u"chiPGH error uid=%d seat=%d cmdSeat=%d",uid,seat,cmd.seatNum % self.seatCount)
        pass


    def executeNextCmd(self,cmd):
        nextSeat = cmd.seatNum % self.seatCount
        chi = cmd.chi
        peng = cmd.peng
        gang = cmd.gang
        hu = cmd.hu
        agang = cmd.agang
        logging.debug(u"执行cmd nextSeat=%d chi=%d peng=%d gang=%d hu=%d",nextSeat,chi,peng,gang,hu)
        nextuser = self.getUser(nextSeat)
        nextuser.sendPacket(mjBuild.noticeCpgh(chi,peng,gang,agang,hu))


    def executeBuPai(self,seat,buKind=mjConst.MO_PAI_NORMAL):
        nextSeat = (seat + 1)% self.seatCount
        logging.debug(u"执行seat=%d补牌操作",nextSeat)
        if len(self.tableCards) > 0:
            mCard = self.tableCards.pop(0)
            nextuser = self.getUser(nextSeat)
            nextuid = nextuser.getUid()
            nextuser.sendPacket(mjBuild.buPai(nextSeat,mCard))
            self.broadcastExcept(mjBuild.buPai(nextSeat,0),nextuid)
            #明杠#暗杠
            handlecards = self.playerMap.get(nextSeat).getHandleCards()
            pengcards = self.playerMap.get(nextSeat).getPengCards()
            gang = mjCheck.instance.checkGang(mCard,pengcards,self.magicCardId)
            hu = mjCheck.instance.checkHu(mCard,handlecards,self.magicCardId)
            agang = mjCheck.instance.checkGang(mCard,handlecards,self.magicCardId)
            g = False
            if gang or hu or agang:
                self.roundCmd.newCmd(o_seat,mCard,False,False,gang,agang,hu)
                logging.debug(u"补牌 自己可以杠or胡")
                cmd = self.roundCmd.getOneCmd()
                self.executeNextCmd(cmd)
            else:
                logging.debug(u"补牌 不能杠or胡")
        else:
            logging.warn(u"没有牌了---->GameOver")
            pass